package com.component.encrypt;

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

public class RSA {
	/** 默认key的大小 */
	private static int KEYSIZE = 1024;

	/**
	 * 获取指定位数密钥对
	 * 
	 * @param n
	 *            位数
	 * @return 密钥对(公钥/密钥)
	 * @throws Exception
	 */
	public static Map<String, String> generateKeyPair(int n) throws Exception {
		/** RSA算法要求有一个可信任的随机数源 */
		SecureRandom sr = new SecureRandom();
		/** 为RSA算法创建一个KeyPairGenerator对象 */
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
		/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
		if (n == 0)
			kpg.initialize(KEYSIZE, sr);
		else
			kpg.initialize(n, sr);
		/** 生成密匙对 */
		KeyPair kp = kpg.generateKeyPair();
		/** 得到公钥 */
		Key publicKey = kp.getPublic();
		byte[] publicKeyBytes = publicKey.getEncoded();
		String pub = new String(Base64.encodeBase64(publicKeyBytes), Config.ENCODING);
		/** 得到私钥 */
		Key privateKey = kp.getPrivate();
		byte[] privateKeyBytes = privateKey.getEncoded();
		String pri = new String(Base64.encodeBase64(privateKeyBytes), Config.ENCODING);

		Map<String, String> map = new HashMap<String, String>();
		map.put("publicKey", pub);
		map.put("privateKey", pri);
		RSAPublicKey rsp = (RSAPublicKey) kp.getPublic();
		BigInteger bint = rsp.getModulus();
		byte[] b = bint.toByteArray();
		byte[] deBase64Value = Base64.encodeBase64(b);
		String retValue = new String(deBase64Value);
		map.put("modulus", retValue);
		return map;
	}

	/**
	 * 生成签名并加密
	 * 
	 * @param data
	 *            需要签名的数据
	 * @param key
	 *            密钥
	 * @return 密文
	 */
	public static byte[] sign(byte[] data, byte[] key) {
		try {
			PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(key);
			KeyFactory keyf = KeyFactory.getInstance("RSA");
			PrivateKey priKey = keyf.generatePrivate(priPKCS8);
			Signature signature = Signature.getInstance("SHA1WithRSA");
			signature.initSign(priKey);
			signature.update(data);
			return signature.sign();
		} catch (Exception e) {
			throw new RuntimeException("sign fail!", e);
		}
	}

	/**
	 * 签名验证
	 * 
	 * @param data
	 *            需验证的数据
	 * @param sign
	 *            签名
	 * @param publicKey
	 *            公钥
	 * @return true/false
	 */
	public static boolean checkSign(byte[] data, byte[] sign, byte[] publicKey) {
		try {
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
			Signature signature = Signature.getInstance("SHA1WithRSA");
			signature.initVerify(pubKey);
			signature.update(data);
			boolean bverify = signature.verify(sign);
			return bverify;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * RSA加密
	 * 
	 * @param source
	 *            原始数据
	 * @param publicKey
	 *            公钥
	 * @param type
	 *            算法/模式/填充
	 * @return 密文
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] source, byte[] publicKey, String type) throws Exception {
		Key key = getPublicKey(publicKey);
		/** 得到Cipher对象来实现对源数据的RSA加密 */
		Cipher cipher = Cipher.getInstance(type);
		cipher.init(Cipher.ENCRYPT_MODE, key);
		/** 执行加密操作 */
		return cipher.doFinal(source);
	}

	/**
	 * RSA解密
	 * 
	 * @param cryptograph
	 *            解密数据
	 * @param privateKey
	 *            私钥
	 * @param type
	 *            算法/模式/填充
	 * @return 明文
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] cryptograph, byte[] privateKey, String type) throws Exception {
		Key key = getPrivateKey(privateKey);
		/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
		Cipher cipher = Cipher.getInstance(type);
		cipher.init(Cipher.DECRYPT_MODE, key);
		/** 执行解密操作 */
		return cipher.doFinal(cryptograph);
	}

	/**
	 * 获取公钥
	 * 
	 * @param key
	 *            公钥密文
	 * @return 公钥
	 * @throws Exception
	 */
	public static PublicKey getPublicKey(byte[] key) throws Exception {
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(key));
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}

	/**
	 * 获取私钥
	 * 
	 * @param key
	 *            私钥密文
	 * @return 私钥
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(byte[] key) throws Exception {
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}
}
